iT邦幫忙

2021 iThome 鐵人賽

DAY 30
1

「目前為止,所有建議無疑將幫助你設計出更好的軟體,這些軟體是由具有明確邊界、職責、依賴關係受控的元件所組成。本章的重點是要強調,如果不考慮實作策略的錯綜複雜,那麼你最佳的設計意圖可能會付之一炬」

「想想要如何將你的設計對應到程式碼結構、如何組織程式碼以及在 Runtime & Compile 時期應用哪些解耦模式、在適用的情況下保留選項

「記得要務實些,要考慮到團隊的規模、技術水平以及解決方案的複雜性和時間及預算的限制,並且要注意其他區域(例如資料模型)中的耦合。魔鬼就藏在實作細節中

取自: Clean Architecture (p.250 & p.264)

CH34: 遺漏的章節

讓我們暫時先把「整潔的架構」放在一邊,來看看幾種設計和組織程式碼的方法:

法一: 依套件逐層打包 (Package By Layer)

  • 水平橫向分層架構 (Horizontal Layered Architecture)
    最簡單的一種設計方法,依據技術角度將程式碼水平分層。這些層被用來分類相似型態的東西,層應該只依賴於相鄰的層
    https://ithelp.ithome.com.tw/upload/images/20211016/20138643zH3GxQUlZ7.png

  • 書中圖例:
    https://ithelp.ithome.com.tw/upload/images/20211016/2013864327Wc0zUrbW.png

  • 說明

    • OrdersController: 用來處理來自 Web 的 Request
    • OrdersService: 與訂單有關的「業務邏輯」
    • OrdersRepository: 定義如何存取持久性(Persistent)訂單資訊的介面
    • JDBCOrdersRepository: 存取 DB 的實作細節 (使用 JDBC)
  • 分析

    • 採用這種分層架構作為開始是個好方式
    • 一旦軟體規模複雜度增長,很快就會發現使用三個大桶來裝程式碼是不夠的。你需要更進一步考慮模組化
    • 且,分層架構不會「尖叫」出任何有關業務領域的東西,多個不同業務領域的程式碼都以分層架構擺放、並排時,他們可能看起來很相似

法二: 依功能特性打包 (Package By Feature)

  • 垂直切片劃分 (Vertical Slicing)

    • 基於相關的特性 (Features)、領域概念 (Domain Concept) 或聚合根 (Aggregate Roots) 而做的劃分。所有型態 (Types) 都放置在單一個 Package 當中,該 Package 的命名會反映出分組概念
      https://ithelp.ithome.com.tw/upload/images/20211016/201386438PDZlXQL1h.png
  • 書中圖例:
    https://ithelp.ithome.com.tw/upload/images/20211016/20138643T6eKl6Nb2Q.png

  • 分析

    • 上一節的所有介面和類別都被放置在單一個 Package 中,程式碼的最高層級組織現在「尖叫」出一些關於 Orders 的業務領域內容
    • 另一個好處是,當使用案例 (Use Case) 變更,找出所有需要修改的程式碼會變得更容易

      「在我看來,兩者都不是最理想的選擇」

      取自: Clean Architecture (p.252)


法三: 端口和轉接器 (Ports & Adapters)

  • 以業務/領域為中心的程式碼
    這樣的程式碼庫是由「內部 (Domain)」和「外部 (Infrastructure)」所組成,外部一定要依賴於內部,不會有其他的依賴方式。這種組織原始碼的方式也是一種可行的方法
    https://ithelp.ithome.com.tw/upload/images/20211016/20138643x3cPCWtvdN.png

  • 書中圖例:
    https://ithelp.ithome.com.tw/upload/images/20211016/20138643amVo6Zv2jg.png

  • 分析

    • 注意:圖中的 OrderRepository 已被重新命名為簡單的 "Orders" ,這概念來自於 DDD 當中的建議。「內部」所有內容的命名都應盡量使用 「普及的領域語言 (Ubiquitous Language)」 來表達

法四: 依元件打包 (Package By Component)

  • 基於元件的架構 (Component Based Architecture)
    這是一種混合式方法,目標是將『與單個粗粒度 (Coarse-grained) 有關的所有責任』Bunddle 到單一的 Package 中。這是以服務 (Service) 為中心的軟體系統觀點
    https://ithelp.ithome.com.tw/upload/images/20211018/20138643gpJuIOlO40.png

  • 書中圖例:
    https://ithelp.ithome.com.tw/upload/images/20211018/20138643gnpaYCK7Mb.png

  • 分析

    • 一個關鍵好處是,如果你正在編寫需要對 Orders 進行處理的程式碼,那麼就只會在一個地方撰寫 - OrdersComponent
    • 在元件內部,關注點的分離依然保持不變
    • 業務邏輯與資料持久性是分離的
    • 例: 一個單獨的 OrderService 封裝「與處理訂單有關的所有內容」
  • [補充]: C4 Software Architecture Model

    • 又稱 "Context, Containers, Components, and Code",屬於 Package By Component 的衍生。有興趣的讀者可再自行 Google

組織與封裝

  • 如果將所有型態都宣告為 Public,那麼任何的架構風格都只是一種分組機制而已 (就像文件夾那樣)
    當所有型態都宣告為 Public 時,四種架構方法在語法上都是相同的!
    https://ithelp.ithome.com.tw/upload/images/20211018/20138643Vigh1o8loq.png
  • 請勿濫用 "Public" 修飾子!
  • 鼓勵使用 編譯器 (Compiler) 來強迫團隊遵守架構規則,而非自律
    否則當菜鳥工程師加入團隊、或者專案時程緊急時,就會發生如下情形...
    https://ithelp.ithome.com.tw/upload/images/20211018/20138643IQe4pZsHhK.png

真的被遺漏的章節...

  • 本次挑戰賽之【架構篇】Clean Architecture 共包含 34 個章節及附錄。以下幾章為筆者考量自身能力 (Firmware 非筆者所長 Orz...)、本書精隨,以及時間安排後決定不詳細介紹的章節

CH23: Presenter 與 Humble Object

  • [Design Pattern]: "Humble Object"
    將行為分成兩個模組,其中一個 Humble 模組包含所有難以測試的東西,另一個模組則相反
  • 以 GUI 測試為例,可劃分成 PresenterView 模組
    View: 是難以測試的 Humble Object。不處理資料,僅負責轉移到 GUI 中
    Presenter: 是可測試的物件。負責資料和字串的格式化處理,並將其放在一個稱之為 View Model 的資料結構中,供 View 模組使用

CH28: 測試邊界

  • 脆弱性測試問題 (Fragile Tests Problem)
    測試也是系統的一部分,與系統強烈耦合的測試將導致大量的測試被中斷 (Test Case 前後關聯太強)
  • 不要依賴於易變的東西
    例:GUI 是易變的,則透過 GUI 運行系統的測試套件必是脆弱的
  • 測試 API
    可以建立一個特定的超能力 API 用以驗證所有的業務規則 (可避開安全約束、繞過 DB...等)
    目的是將測試結構和應用程式的結構解耦開來
  • 安全性問題
    某一些測試 API 的超能力是危險的,請將其保存在一個分離的、可獨立部署的元件中加以控管

CH29: 整潔的嵌入式架構

https://ithelp.ithome.com.tw/upload/images/20211017/20138643Wyd7B2s5Vg.png

  • 硬體和韌體會隨時間推移而過時(Obsolete),隨即也需要對軟體做相應改動
  • 未妥善管理的硬體和韌體依賴仍是軟體的頭號殺手
  • 原則:依賴於抽象
    • Operating System Abstraction Layer (OSAL)
    • Hardware Abstraction Layer (HAL)

CH33: 案例研究 - 影片販售

  • 使用案例 (Use Cases) 分析
  • 元件架構
  • 依賴管理

Reference

  1. Horizontal and Vertical Layers in Software Development
  2. concept persistence layer in category .net
  3. Chapter 1. Layered Architecture
  4. Package by Feature
  5. Hexagonal Architecture with Java and Spring
  6. Ports & Adapters Architecture
  7. Hexagonal Architecture with Java and Spring
  8. 戰略設計:重點回顧以及比喻
  9. Coarse-grained vs fine-grained
  10. Component Based Architecture
  11. 用于软件架构的 C4 模型
  12. 軟體架構之C4模型
  13. The C4 model for visualising software architecture
  14. gotoberlin2018-modular-monoliths
    意外查到的演講投影片,內容幾乎就是 Chapter 34 的詳細補充,有興趣可自行深入研究

上一篇
Day 29: 細節:資料庫、Web、框架 (待改進中... )
下一篇
Day 31: 【全系列終】架構考古學
系列文
成為乾淨的開發者吧! Clean Code, Clean Coder, Clean Architecture 導讀之旅31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言